#|

L.I.S.P. = Lots of irritating and silly parentsis

I hate beuracry software.
Making your life even more paintful. 

|- Form
  |- List of commands
  |  |- Start a new section - Starts a new section in the, and stores the next given variables in groups
  |  |  |- Section info - Struct that keeps the section name and set variables during it
  |  |- Show a message
  |  |- Show a message with input variables
  |  |- Print information about all sections
  |  |- Process value - Stores a new value returned from the given lambda
  |  |  |- General lambda input
  |  |  |- Sum a given list of values
  |  |- Question - Stores the answer in the main data structure
  |  |  |- Simple question - string output
  |  |  |- List question - Shows a question that can take more than a single input and stores them in a list
  |  |  |  |-Get size
  |  |  |  |-Numberic list - Shows a question and takes any number of inputs
  |  |  |  |  |-Get Sum
  |  |  |- Boolean input - [y/n] answer
  |  |  |- Option list - Select one item from a list
  |  |  |- Numeric input
  |  |- Conditional - Executes a list of commands if true
  |  |  |- Lambda
|# 

#| +++++++++++ Form +++++++++++ |#

;; A form is a command list
(define-struct form ( commands ))

#| +++++++++++ List of commands +++++++++++ |#

;;A command list of a commands
(define-struct cmd-list (cmds))

#| +++++++++++ Commands +++++++++++ |#

;;a key is a string
;;A key that will correspond to a value in the form

;;a data is a (make-data string mixed)
;;Keeps information about the form in key-value structure
(define-struct data (key value))

#| +++++++++++ Section +++++++++++ |#
;;A section is a (make-section string string)
;;A new section is going to set a global variable and define all the next given intake variables into a list
(define-struct section (name description))

;;a section-info is a (make-section-info string list[string])
;;Keeps the section name and set variables during it
(define-struct section-info (name keylist))
#| ----------- END OF Section ----------- |#

;;a message is a (make-message string)
;;Prints the given message to the output window
(define-struct message (input))

;;a message-var is a (make-message string key)
;;Prints the formated string with the given input variable names
(define-struct message-var(input key))

;;a process-value is a (make-process-value key function)
;;process the given function and stores it in the key
(define-struct process-value( key func))

;;a process-sum-values is a (make-process-sum-values key list[key])
;;Sums all the numeric keys and saves it in the given key
(define-struct process-sum-values(key key-list))

;;a print-sections is a (make-print-sections)
;;Prints in detail all the information in all sections
(define-struct print-sections ())

#| +++++++++++ Question +++++++++++ |#
;;A question can be either a:
;; -question
;; -question-list
;; -question-numeric-list
;; -question-boolean
;; -question-numeric
;; -question-choice

;;a question is a (make-question key string)
;;Asks the user for the question and stores it in the input
(define-struct question (key question))

;;a question-list is a (make-question-list key string)
;;Asks the user for an undertemindate size of input
(define-struct question-list(key question))

;;a question-numeric-list is a (make-question-numeric-list key string)
;;Asks the user for a list of numbers
(define-struct question-numeric-list (key question))

;;a question-boolean is a (make-question-boolean key string)
;;Asks the user for a boolean input only
(define-struct question-boolean (key question))

;;a question-numeric is a (make-question-numeric key string)
;;Asks the user for a numeric input only
(define-struct question-numeric (key question))

;;a question-choice is a (make-question-choice key string list[string])
;;Choose one item the list of strings and store the value in the key
(define-struct question-choice(key question options))


#| ----------- END OF Question ----------- |#                        

#| +++++++++++ Conditional +++++++++++ |#

;;a conditional is a (make-conditional function list[cmd] list[cmd])
;;A condtional checks for the function and executes the list of commands if necessary
(define-struct conditional (func cmd-list f-cmd-list))

#| ----------- END OF Conditional ----------- |#
#| ----------- END OF Commands ----------- |#
#| ----------- END OF List of Commands ----------- |#
#| ----------- END OF Form ----------- |#

#| +++++++++++ SYNTAX HELPERS +++++++++++ |#

(define-syntax question-choice
  (syntax-rules()
    [(question-choice key question (args ...))
     (make-question-choice key question (list args ...))
     ]))

(define-syntax check-bool
  (syntax-rules()
    [(chech-bool key args ...)
     (check (lambda () (boolean=? (get-value key) #t)) args ...)]
    ))

(define-syntax check 
  (syntax-rules()
    [(check func list1 list2)
     (make-conditional func list1 list2)]
    [(check func [args ...])
     (make-conditional func (list args ...) empty)]
    [(check func [args ...] [false-args ...])
     (make-conditional func (list args ...) (list false-args ...))]
    ))

(define-syntax sum-values
  (syntax-rules()
    [(sum-values key (args ...))
     (make-process-sum-values key (list args ...))
     ]))

(define-syntax subtract
  (syntax-rules()
    [(subtract key val1 val2)
     (make-process-value key (lambda() ( - (get-value val1) (get-value val2) )))
     ]))

(define-syntax subtract-positive
  (syntax-rules()
    [(subtract-positive key val1 val2)
     (make-process-value key (lambda() (max 0 ( - (get-value val1) (get-value val2) ))))
     ]))


(define-syntax question-numeric
  (syntax-rules()
    [(question-numeric key args)
     (make-question-numeric key args)
     ]
    [(question-numeric key)
     (make-question-numeric key key)
     ]))

(define-syntax new-form
  (syntax-rules()
    [(new-form cmds ...)
     (make-form (list
                 cmds ...
                 ))]
    [(question args ...) (make-question args ...)]
    [(section args ...) (make-section args ...)]
    [(question-boolean args ...) (make-question-boolean args ...)]
    [(question-list args ...) (make-question-list args ...)]
    ))


#| ----------- END OF SYNTAX HELPERS ----------- |#

(define (calculate-tax)
  [let [(income (get-value "Taxable income"))]
    [cond [(> income 150000)
           (* income .33)]
          [(> income 75000)
           (* income .28)]
          [(> income 30000)
           (* income .17)]
          [else
           income]]])

(define Schedule-A
  (new-form
   (section "Schedule A" "More input!")
   (question-numeric "Medical and dental expenses")
   (make-process-value "Total Medical expenses" 
                       (lambda() ( - 
                                   (get-value "Medical and dental expenses")
                                   (* (get-value "Adjusted gross income") 0.075))))
   
   (question-numeric "State and local income taxes")
   (question-numeric "Real estate taxes")
   (question-numeric "Personal property taxes")
   (sum-values "Total Taxes You Paid" ("State and local income taxes" 
                                       "Real estate taxes"
                                       "Personal property taxes" ))
   
   (question-numeric "Home mortgage interest")
   (question-numeric "Investment interest")
   (sum-values "Total Interest You Paid" ("Home mortgage interest" 
                                          "Investment interest"))
   
   
   (question-numeric "Gifts by cash or check")
   (question-numeric "Gifts Other than by cash or check")
   (question-numeric "Carryover from prior year")
   (sum-values "Total Gifts to Charity" ("Gifts by cash or check" 
                                         "Gifts Other than by cash or check"
                                         "Carryover from prior year" ))
   
   (question-numeric "Unreimbursed employee expenses")
   (question-numeric "Tax preparation fee")
   (question-numeric "Other expenses—investment" "Other expenses—investment, safe deposit box, etc.")
   (sum-values "Sum Job Expenses" ("Unreimbursed employee expenses" 
                                   "Tax preparation fee"
                                   "Other expenses—investment" ))
   (make-process-value "Total Job Expenses" 
                       (lambda() (max 0 ( - 
                                          (get-value "Sum Job Expenses")
                                          (* (get-value "Adjusted gross income") 0.02)))))
   
   
   (check ( lambda()( > (get-value "Adjusted gross income") 150500))
          [list (make-process-value "Itemized deductions" (lambda() 137300))]
          [list (sum-values "Itemized deductions" ("Total Medical expenses"  
                                                   "Total Taxes You Paid"
                                                   "Total Interest You Paid" 
                                                   "Total Gifts to Charity" 
                                                   "Total Job Expenses" ))])
   )
  )

(define Form1040 
  (new-form 
   (section "Label" "Basic personal information")
   (question "First Name" "Your first name")
   (question "Last Name" "Your last name")
   (question "Social security" "Your social security number (XXX-XX-XXXX)")
   (question "Home address" "Enter your home street and number")
   
   
   (section "Filing Status" "Enter your filling status")
   (question-choice "Filling Status" 
                    "What is your filling status?" 
                    ("Single" "Head of houseold" "Qualifying widow(er) with dependent child."))
   
   
   (section "Exemptions" "Persons that are depended")
   (question-boolean "Exemptions-yourself" "Are you depended on yourself?")
   (question-boolean "Exemptions-spouse" "Is your wife depended on yourself?")
   (check-bool  "Exemptions-spouse"
                [(question "Spouse-name" "Enter the spouse name")])
   (question-list "other-dependets" "Enter the name and social security number of any other depenents")
   
   
   (section "Income" "Enter the personal or general income")
   (question-numeric "wages" "What is your wages, salaries, tips, etc.")
   
   
   (question-numeric "taxable" "Taxable interest.")
   (question-numeric "Ordinary dividends" "Ordinary dividends.")
   (question-numeric "IRA-distributions" "IRA distributions")
   (question-numeric "Pensions-annuities" "Pensions and annuities")
   (question-numeric "Social-security-benefits" "Social security benefits")
   (question-numeric "Other income" "Other income")
   (sum-values "total-income" ("wages" "taxable" "Ordinary dividends" 
                                       "IRA-distributions" "Pensions-annuities" 
                                       "Social-security-benefits" "Other income"))
   
   
   (section "Adjusted Gross Income" "Calculation of an individual's income tax liability.")
   (question-numeric "IRA deduction" "IRA deduction")
   (question-numeric "Student loan interest" "Student loan interest deduction ")
   (question-numeric "Jury duty pay" "Jury duty pay you gave to your employe")
   (sum-values "total-income" ("IRA deduction" "Student loan interest" "Jury duty pay"))
   (subtract "Adjusted gross income" "total-income" "total-income")
   
   
   (section "Tax and Credits" "Calculating your total taxes")
   (question-boolean "Blind-or-old" "Are you born before January 2, 1942 or blind?")
   (check-bool  "Blind-or-old"
                [list (make-process-value "Itemized deductions" (lambda() 5000 ))]
                [list 
                 (question-boolean "use-schedule-a" "Do you wish to use shecule A?")
                 (check-bool  "use-schedule-a"
                              Schedule-A
                              [list (question-numeric "Itemized deductions" "Enter your Itemized deductions")]
                              )])
   
   (section "Tax and Credits" "Part 2")
   (subtract "New income" "Adjusted gross income" "Itemized deductions")
   (make-process-value "Total exemptions" (lambda () (* 3300 (input-length "other-dependets"))))
   (subtract-positive "Taxable income" "New income" "Total exemptions")
   (make-process-value "Tax" calculate-tax)
   (question-numeric "Foreign tax credit" "Foreign tax credit")
   (question-numeric "Education credits" "Education credits")
   (sum-values "total credits" ("Foreign tax credit" "Education credits"))
   (subtract-positive "Tax and credits" "Tax" "total credits")
   
   
   (section "Other taxes" "Other taxes")
   (question-numeric "Self-employment tax" "Self-employment tax")
   (question-numeric "SS and Medicare tax" 
                     "Social security and Medicare tax on tip income not reported to employer")
   (sum-values "total tax" ("Tax and credits" "Self-employment tax" "SS and Medicare tax"))
   
   
   (section "Payment" "Payment")
   (question-numeric "Federal income tax" "Federal income tax")
   (question-numeric "2006 estimated tax payments" " 2006 estimated tax payments and amount applied from 2005 return")
   (sum-values "total payments" ("Federal income tax" "2006 estimated tax payments"))
   
   (section "Refund" "Refund")
   (subtract-positive "Refund" "total payments" "total tax")
   
   (print-sections)
   )
  )







